import { isArray, isNil, cloneDeep } from 'lodash-es'

export function hasOwn<T extends object>(target: T, key: PropertyKey) {
    return Object.prototype.hasOwnProperty.call(target, key) && !isNil(target)
}

export function omit<T extends object, K extends keyof T>(target: T, key?: K, deep?: boolean): Omit<T, K>
export function omit<T extends object, KS extends (keyof T)[]>(
    target: T,
    keys?: KS,
    deep?: boolean
): Omit<T, KS[number]>
export function omit<T extends object>(target: T, keys: PropertyKey | PropertyKey[] = [], deep = false): any {
    const keySet = new Set(!isArray(keys) ? [keys] : keys)
    return Object.entries(target).reduce((result, [key, value]) => {
        if (!keySet.has(key)) {
            result[key] = deep ? cloneDeep(value) : value
        }
        return result
    }, {} as Record<PropertyKey, any>)
}

export function pick<T extends object, K extends keyof T>(target: T, key?: K, deep?: boolean): Pick<T, K>
export function pick<T extends object, KS extends (keyof T)[]>(
    target: T,
    keys?: KS,
    deep?: boolean,
): Pick<T, KS[number]>
export function pick<T extends object>(target: T, keys: PropertyKey | PropertyKey[] = [], deep = false): any {
    const keySet = new Set(!isArray(keys) ? [keys] : keys)
    return Object.entries(target).reduce((result, [key, value]) => {
        if (keySet.has(key)) {
            result[key] = deep ? cloneDeep(value) : value
        }
        return result
    }, {} as Record<PropertyKey, any>)
}
